import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QTextEdit, QPushButton, QVBoxLayout, QWidget, QMessageBox, QListWidget, QListWidgetItem
from PyQt5.QtNetwork import QUdpSocket, QHostAddress
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QPainter, QBrush, QColor, QPen
from hashlib import sha256
from datetime import datetime
import random
import os
import re

verifyFlag = False
submitFlag = False
accountId = None 
contact = None
contactId = None

class LoginWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Login")
        self.setGeometry(100, 100, 380, 150)

        self.login_label = QLabel("Login:", self)
        self.login_label.move(20, 20)

        self.password_label = QLabel("Password:", self)
        self.password_label.move(20, 50)

        self.repeat_label = QLabel("Repeat:", self)
        self.repeat_label.move(20, 80)

        self.login_input = QLineEdit(self)
        self.login_input.move(100, 20)

        self.password_input = QLineEdit(self)
        self.password_input.move(100, 50)
        self.password_input.setEchoMode(QLineEdit.Password)

        self.repeat_input = QLineEdit(self)
        self.repeat_input.move(100, 80)
        self.repeat_input.setEchoMode(QLineEdit.Password)

        self.login_button = QPushButton("Register", self)
        self.login_button.move(250, 20)
        self.login_button.clicked.connect(self.login)
  
        self.verify_button = QPushButton("Login", self)
        self.verify_button.move(250, 50)
        self.verify_button.clicked.connect(self.verify)

        self.socket = QUdpSocket(self)

    def login(self):
        global accountId
        login = self.login_input.text()
        password = self.password_input.text()
        repeatPass = self.repeat_input.text()

        if password != repeatPass:
            QMessageBox.warning(self, "Password Mismatch", "Passwords do not match.")
            self.password_input.clear()
            self.repeat_input.clear()
            return
        else:
            hashed_password = sha256(password.encode()).hexdigest()
            data = f"newuser|{login}|{hashed_password}".encode()
            host = QHostAddress("127.0.0.1")
            port = 20231
            self.socket.writeDatagram(data, host, port)
            print(data)

            if self.socket.waitForReadyRead():
                while self.socket.hasPendingDatagrams():
                    data, senderHost, senderPort =  self.socket.readDatagram(self.socket.pendingDatagramSize())
                    accountId = ord(data.decode())
                    print(f"Received message: {accountId} from {senderHost.toString()}:{senderPort}")
                    print(accountId)

            QMessageBox.information(self, "Registration", "Success!")

    def verify(self):
        global verifyFlag
        if verifyFlag == True:
            self.submitVerify()
            return
        else:
            verifyFlag = True
            self.repeat_input.deleteLater()
            self.repeat_label.deleteLater()
            self.login_button.deleteLater()
            print(verifyFlag)
            return verifyFlag
 
    def submitVerify(self):
        global accountId
        login = self.login_input.text()
        password = self.password_input.text()
        print(f"{login} {password}")
        hashed_password = sha256(password.encode()).hexdigest()
        data = f"verify|{login}|{hashed_password}".encode()
        host = QHostAddress("127.0.0.1")
        port = 20231
        self.socket.writeDatagram(data, host, port)
        if self.socket.waitForReadyRead():
            while self.socket.hasPendingDatagrams():
                data, senderHost, senderPort = self.socket.readDatagram(self.socket.pendingDatagramSize())
                try:
                    accountId = ord(data.decode())
                    print(f"Received message: {accountId} from {senderHost.toString()}:{senderPort}")
                    window.close()
                except:
                    self.catch()

   
    def catch(self):
        QMessageBox.warning(self, "Error!", "Verify error!")
        self.password_input.clear()
        self.login_input.clear()
        print(f"Verify error!")                
                    
        

class ChatClient(QMainWindow):
    def __init__(self):
        super().__init__()
	
        self.contact = contact
	
        self.setWindowTitle("Chat Client")
        self.setGeometry(100, 100, 650, 400)

        self.message_input = QTextEdit(self)
        self.message_input.setGeometry(20, 250, 300, 30)

        self.send_button = QPushButton("Send", self)
        self.send_button.move(320, 250)
        self.send_button.clicked.connect(self.send_message)
        #self.message_input.returnPressed.connect(self.send_message)

        self.log_list = QListWidget(self)
        self.log_list.setGeometry(20, 20, 400, 200)
        
        self.contacts_list = QListWidget(self)
        self.contacts_list.setGeometry(430, 20, 180, 200)

        self.add_contact_input = QLineEdit(self)
        self.add_contact_input.setGeometry(430, 250, 180, 30)
        self.add_contact_input.returnPressed.connect(self.add_contact)

        self.load_contacts()
        self.setup_contacts_list()

        self.socket = QUdpSocket(self)
        #self.socket.bind("127.0.0.1", 20231)
        self.socket.readyRead.connect(self.receive_message) 


    def send_message(self):
        message = self.message_input.toPlainText()
        if message:
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            receive_id = accountId
            get_id = contactId

            data = f"insert|{current_time}|{receive_id}|{get_id}|{message}".encode()
            host = QHostAddress("127.0.0.1")
            port = 20231
            self.socket.writeDatagram(data, host, port)

            self.message_input.clear()
            self.log_message(f"[{current_time}] You: {message}")
            
    def get_messages(self):
        host = QHostAddress("127.0.0.1")
        port = 20231
        receive_id = accountId
        get_id = contactId
        print(f" {accountId}      {contactId}")
        data = f"getmessages|{receive_id}|{get_id}".encode()
        self.socket.writeDatagram(data, host, port)

    def log_message(self, message):
        self.log_list.addItem(message)
    
    def start_chat(self, contact):
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.log_list.clear()
        self.log_message(f"[{current_time}] Chat with {contact}")
        self.get_messages()
    
    def handle_contact_doubleclick(self, item: QListWidgetItem):
        global contact, contactId
        contact = item.text()
    
        contact_name, contact_id = contact.split(" (ID: ")
        contact_id = contact_id[:-1]  
    
        contactId = contact_id  
        contact = contact_name 
        self.start_chat(contact_name)
        print(f"{contact}      {contactId}")
     
    def setup_contacts_list(self):
        self.contacts_list.itemDoubleClicked.connect(self.handle_contact_doubleclick)
            
    def request_contact(self, contact):
        data = f"getcontact|{contact}".encode()
        host = QHostAddress("127.0.0.1")
        port = 20231
        self.socket.writeDatagram(data, host, port)
    
    def save_contact(self, login, id):
        filename = f"{login}.txt"
        with open(filename, "w") as file:
            file.write(str(id))
        
    
    def load_contacts(self):
        for filename in os.listdir():
            if filename.endswith(".txt"):
                with open(filename, "r") as file:
                    id = int(file.read())
                    self.contacts_list.addItem(f"{filename[:-4]} (ID: {id})")
    
    def add_contact(self):
        contact = self.add_contact_input.text()
        if contact:
            self.request_contact(contact)
    
    def log_sort(self, message_logYou, message_logContact):
        combined_list = message_logYou + message_logContact

        sorted_list = sorted(combined_list, key=lambda x: x[0][1:20])

        print(sorted_list)

    
    def receive_message(self):
        host = QHostAddress("127.0.0.1")
        port = 20231
        while self.socket.hasPendingDatagrams():
            datagram, host, port = self.socket.readDatagram(self.socket.pendingDatagramSize())
            received_message = datagram.decode()

            if received_message.startswith("{ok,[<<\"id\">>,<<\"login\">>]"):
                match = re.match(r'{ok,\[\<<\"id\"\>\>,\<<\"login\"\>\>\],\[\[(\d+),\<<\"(.+?)\"\>>\]\]\}', received_message)
                if match:
                    id = int(match.group(1))
                    login = match.group(2)
                    
                    self.save_contact(login, id)
                    self.contacts_list.addItem(f"{login} (ID: {id})")
                    print(f"Added contact: {login} (ID: {id})")
            
            if received_message.startswith("[[\""):
               print("ok")
               time_list = []
               message_list = []
               data_list = received_message.split('],\n [')
               for data in data_list:
               	   
                   data = data.strip(']')
                   data = data.strip("[[\"")
                   time, message = data.split('","')
                   time_list.append(time.strip('"'))
                   message_list.append(message.strip('"'))

                   message_log_contact = list(zip(time_list, message_list))
                   message_logContact = [(f"[{time}]  {contact}: {message}",) for time, message in message_log_contact]
               print(message_logContact)

               for time, message in message_log_contact:
                   self.log_list.addItem(f"[{time}] {contact}: {message}")
             
            if received_message.startswith("You:[[\""):
               print("ok")
               time_list = []
               message_list = []
               data_list = received_message.split('],\n [')
               for data in data_list:
               	   
                   data = data.strip(']')
                   data = data.strip("You:[[\"")
                   time, message = data.split('","')
                   time_list.append(time.strip('"'))
                   message_list.append(message.strip('"'))

                   message_log_you = list(zip(time_list, message_list))
                   message_logYou = [(f"[{time}] You: {message}",) for time, message in message_log_you]
               print(message_logYou)
               for time, message in message_log_you:
                   self.log_list.addItem(f"[{time}] You: {message}")
            #self.log_sort(message_logYou, message_logContact)
              
                
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = LoginWindow()
    window.show()
    app.exec_()

    if window.close() and verifyFlag == True:
       chat = ChatClient()
       chat.show()
    
       sys.exit(app.exec_())
